// Copyright (c) 2006 Zorm
// Released under the MIT License

#include "PCH.h"
#include "Common.h"

static bool CheckRequirements();
static void FatalError(const TCHAR *errorMessage);
LONG WINAPI ATHUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo);

bool stopLoop = false;
ATH *ATH::instance = 0;

INT WINAPI WinMain(HINSTANCE instance, HINSTANCE notUsed, LPSTR cmdLine, int cmdShow) {

	if (!CheckRequirements()) {
		FatalError(TEXT("This system does not meet the requirements to run ATH. Please refer to the help documentation"));
		return 0;
	}

	SetUnhandledExceptionFilter(ATHUnhandledExceptionFilter);

	int ret = ATH::Instance()->GetConfig()->LoadConfig();
	if (ret == -1) {
		FatalError(TEXT("Failed to load configuration file!"));
		return 0;
	} else if (ret > 0) {
		tstringstream sstr;
		sstr << TEXT("Error parsing configuration file on line ") << ret;
		FatalError(sstr.str().c_str());
		return 0;
	}

	ATH::Instance()->SetMainWindow(instance);
	if (!ATH::Instance()->GetMainWindow()->CreateWindows()) {
		FatalError(TEXT("Unable to create windows!"));
		return 0;
	}
	
	ATH::Instance()->GLInit();
	if (!ATH::Instance()->GetGLContext()->Init()) {
		FatalError(TEXT("Failed to setup openGL!"));
		return 0;
	}

	ATH::Instance()->GetMainWindow()->Show();
	ATH::Instance()->GetMainWindow()->Update();

	ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("Anticipating the Hook version %i.%i.%i.%i, compiled on %s at %s.\n"), PRODUCTVER, TEXT(__DATE__), TEXT(__TIME__));

	//NIDSParser *parser = new NIDSParser(TEXT("test.nids"));
	//NIDSProductDescription productDesc = parser->GetProductDescription();
	//ATH::Instance()->GetRadarInfo()->SetLatitude(productDesc.latitude);
	//ATH::Instance()->GetRadarInfo()->SetLongitude(productDesc.longitude);
	//ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("%f %f\n"), productDesc.latitude, productDesc.longitude);
	//delete parser;	
	
	ATH::Instance()->LoadRadar(TEXT("test.nids"));

	/*SHPHandle shpHandle = SHPOpen("c_16mr06", "rb");
	int entities = 0, shapeType = 0;
	SHPGetInfo(shpHandle, &entities, &shapeType, NULL, NULL);
	ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("%i %i\n"), entities, shapeType);
	for (int i = 0; i < entities; i++) {
		SHPObject *shpO = SHPReadObject(shpHandle, i);
		ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("%i %i %i %f %f\n"), shpO->nParts, shpO->nVertices, shpO->nSHPType, shpO->padfX[0], shpO->padfY[0]);
		SHPDestroyObject(shpO);
	}
	SHPClose(shpHandle);
	delete parser;*/

	HWND mainWindowHWND = ATH::Instance()->GetMainWindow()->getHWND();
	while(!stopLoop) {
		if(MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE) == WAIT_OBJECT_0) {
			MSG msg;
			while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
				if (msg.message == WM_QUIT) {
					stopLoop = true;
				}
				if(!IsDialogMessage(mainWindowHWND, &msg)) {
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}
		}
	}

	ATH::Instance()->GetConfig()->Save();

	ATH::Instance()->CleanUp();

	#ifdef _DEBUG
	//_CrtDumpMemoryLeaks();
	#endif

	return 0;
	UNREFERENCED_PARAMETER(cmdShow);
	UNREFERENCED_PARAMETER(cmdLine);
	UNREFERENCED_PARAMETER(notUsed);
}

static bool CheckRequirements() {
	OSVERSIONINFOEX osvi;
	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
		return false;
	}
	if (osvi.dwMajorVersion >= 5) {
		return true; //Win2k or later
	}
	return false;
}

static void FatalError(const TCHAR *errorMessage) {
	MessageBox(NULL, errorMessage, TEXT("ATH fatal error"), MB_ICONERROR);
}

ATH *ATH::Instance() {
	if (!instance) {
		instance = new ATH();
	}
	return instance;
}

ATH::ATH() {
	log = new Log();
	config = new Config(TEXT("ATH.conf"));
	sites = new RadarSites();
	//radarInfo = new RadarInformation(TEXT(""));
	radarManager = new RadarManager();
	glcontext = NULL;
}

ATH::~ATH() {
	delete sites;
	delete radarManager;
	delete glcontext;
	delete mainWindow;
	delete config;
	delete log;
}

LONG WINAPI ATHUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) {

	PROCESS_INFORMATION pi;
	STARTUPINFOW si;
	ZeroMemory(&si, sizeof(STARTUPINFOW));
	
	std::wostringstream wstr;
	wstr << L"ZormCrashDump.exe " << GetCurrentProcessId() << L" " << GetCurrentThreadId() << L" " << (DWORD_PTR)ExceptionInfo;
	
	CreateProcessW(NULL, (LPWSTR)wstr.str().c_str(), NULL, NULL, false, 0, NULL, NULL, &si, &pi);
	
	WaitForSingleObject(pi.hProcess, INFINITE);
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
	
	return EXCEPTION_CONTINUE_SEARCH;

}
